import java.util.*;
import java.lang.Math;

class Pyramid
{
    double[] w;
    double[][] g;
    double[][] l;
    
    public Pyramid(double[] motion)
    {
        this.w = new double[5];
        this.w[0] = 0.0625;
        this.w[1] = 0.25;
        this.w[2] = 0.375;
        this.w[3] = 0.25;
        this.w[4] = 0.0625;
        int n = (int)(Math.log(motion.length)/Math.log(2));
        this.g = new double[n][motion.length];
        this.g[0] = motion;
        this.l = new double[n-1][motion.length];
        this.createPyramids();
    }
    
    public double[][] getLaplacian()
    {
        return l;
    }
    
    public void addLaplacian(int i, double[] x)
    {
        for (int j = 0; j < l[i].length; j++)
            l[i][j] = (l[i][j] + x[j]) / 2.0;
    }
    
    public void multiplyLaplacian(int i, double x)
    {
        for (int j = 0; j < l[i].length; j++)
            l[i][j] = l[i][j] * x;
    }
    
    public int laplacianSize()
    {
        return this.l.length;
    }
    
    public double[] reconstruct()
    {
        double[] signal = g[g.length-1];
        for (int i = 0; i < signal.length; i++)
        {
            for (int j = 0; j < l.length; j++)
            {
                signal[i] += l[j][i];
            }
        }
        return signal;
    }
    
    public void printGaussian()
    {
        for (int i = 0; i < this.g.length; i++)
        {
            for (int j = 0; j < this.g[i].length; j++)
                System.out.print(this.g[i][j] + " ");
            System.out.println("");
        }
    }
    
    public void printLaplacian()
    {
        for (int i = 0; i < this.l.length; i++)
        {
            for (int j = 0; j < this.l[i].length; j++)
                System.out.print(this.l[i][j] + " ");
            System.out.println("");
        }
    }
    
    private void createPyramids()
    {
        this.createGaussian();
        this.createLaplacian();
    }
    
    private void createGaussian()
    {
        for (int k = 0; k < (this.g.length - 1); k++)
        {
            for (int i = 0; i < this.g[k].length; i++)
            {
                this.g[k + 1][i] = 0;
                for (int m = -2; m <= 2; m++)
                {
                    double x;
                    if ((i + (Math.pow(2, k) * m)) < 0)
                    {
                        x = this.g[k][0];
                    }
                    else if ((i + (Math.pow(2, k) * m)) >= this.g[k].length-1)
                    {
                        x = this.g[k][this.g[k].length-1];
                    }
                    else
                    {
                        x = this.g[k][i + (int)(Math.pow(2, k) * m)];
                    }
                    this.g[k + 1][i] += this.w[m + 2] * x;
                }
            }
        }
    }
    
    private void createLaplacian()
    {
        for (int k = 0; k < this.l.length; k++)
        {
            for (int i = 0; i < this.l[k].length; i++)
                this.l[k][i] = this.g[k][i] - this.g[k + 1][i];
        }
    }
}
